<template>
  <div v-loading="loading" class="app-container">
    <div id="map" ref="map" style="width: 100%; height: 872px" />
    <div class="colors">
      <dl v-for="(item, index) in steps" :key="index" class="flex">
        <dt :style="{ background: item.color }" @click="changeStep(item.step)">
          <i
            :class="
              +item.step === +step
                ? 'el-icon-circle-check'
                : 'el-icon-remove-outline'
            "
            class="mr12 font20"
          />{{ item.lower + " ~ " + item.upper }}
        </dt>
      </dl>
    </div>
    <div class="tools">
      <el-dropdown class="mr12" @command="handleCommand">
        <el-button type="default">
          载入底图<i class="el-icon-arrow-down el-icon--right" />
        </el-button>
        <el-dropdown-menu slot="dropdown">
          <el-dropdown-item
            v-for="(item, index) in gridPartitions"
            :key="index"
            :command="item"
          >
            {{ item.name }}
          </el-dropdown-item>
        </el-dropdown-menu>
      </el-dropdown>
      <el-button
        type="default"
        class="mr12"
        @click="clearKriging"
      >清除分区<i
        class="el-icon-close el-icon--right"
      /></el-button>
      <el-select
        v-model="gridTypeId"
        class="mr12"
        placeholder="分区方式"
        filterable
        style="width: 100px"
      >
        <el-option
          v-for="(item, index) in gridTypes"
          :key="index"
          :label="item.name"
          :value="item.id"
        />
      </el-select>
      <el-button
        type="primary"
        @click="dialogVisible = true"
      >生成分区</el-button>
    </div>
    <el-dialog title="设置默认填充颜色" :visible.sync="dialogColorVisible" width="400px">
      <div class="colors" style="position:inherit;">
        <dl v-for="(item, index) in steps" :key="index" class="flex">
          <dt :style="{ background: item.color }" style="width:100%;" @click="changeStep(item.step)">
            <i
              :class="
                +item.step === +step
                  ? 'el-icon-circle-check'
                  : 'el-icon-remove-outline'
              "
              class="mr12 font20"
            />{{ item.lower + " ~ " + item.upper }}
          </dt>
        </dl>
        <div class="h12" />
        <el-button type="primary" @click="_drawFinish()">确认</el-button>
      </div>
    </el-dialog>
    <el-dialog title="分区参数设置" :visible.sync="dialogVisible" width="700px">
      <div>
        <el-form
          ref="ruleForm"
          :model="ruleForm"
          :rules="rules"
          label-width="100px"
          class="demo-ruleForm"
        >
          <el-row>
            <el-col :span="12">
              <el-form-item
                label="设备选择"
                prop="serialno"
              ><el-select
                v-model="ruleForm.serialno"
                placeholder="喷灌机"
                filterable
                clearable
                style="width:100%;"
              >
                <el-option
                  v-for="(item, index) in sprinklers"
                  :key="index"
                  :label="item.name"
                  :value="item.serialno"
                /> </el-select></el-form-item></el-col>
            <el-col :span="12">
              <el-form-item
                label="分区角度"
                prop="angle"
              ><el-input-number
                v-model="ruleForm.angle"
                controls-position="right"
                class="mr12"
                placeholder="分区角度"
                clearable
                :min="1"
                :max="360"
                style="width:100%;"
              >
                <template slot="append">°</template>
              </el-input-number></el-form-item></el-col>
          </el-row>
          <el-row>
            <el-col :span="12">
              <el-form-item
                label="开始角度"
                prop="startAngle"
              ><el-input-number
                v-model="ruleForm.startAngle"
                controls-position="right"
                placeholder="开始角度"
                clearable
                :min="0"
                :max="360"
                style="width:100%;"
              >
                <template slot="append">°</template>
              </el-input-number></el-form-item></el-col>
            <el-col :span="12">
              <el-form-item
                label="结束角度"
                prop="endAngle"
              ><el-input-number
                v-model="ruleForm.endAngle"
                controls-position="right"
                class="mr12"
                placeholder="结束角度"
                clearable
                :min="0"
                :max="360"
                style="width:100%;"
              >
                <template slot="append">°</template>
              </el-input-number></el-form-item></el-col>
          </el-row>
          <el-form-item
            label="控制节点"
            prop="distances"
          ><el-table
            border
            :data="ruleForm.distances"
            style="width: 100%"
            :max-height="500"
          >
            <el-table-column
              prop="date"
              label="距中心点距离"
              align="center"
            >
              <template #default="{row}">
                <el-input-number v-model="row.distance" controls-position="right" placeholder="距中心点距离" />
              </template>
            </el-table-column>
            <el-table-column
              prop="name"
              label="起始喷头"
              align="center"
            >
              <template #default="{row}">
                <el-input-number v-model="row.spstart" controls-position="right" placeholder="起始喷头" />
              </template>
            </el-table-column>
            <el-table-column
              prop="address"
              align="center"
              label="结束喷头"
            >
              <template #default="{row}">
                <el-input-number v-model="row.spend" controls-position="right" placeholder="结束喷头" />
              </template>
            </el-table-column>
            <el-table-column label="操作" align="center" width="80">
              <template #header>
                <el-link icon="el-icon-plus" type="primary" @click="addDistance">增加</el-link>
              </template>
              <template #default="{row,$index}">
                <el-link icon="el-icon-delete" type="danger" @click="deleteDistance($index)">删除</el-link>
              </template>
            </el-table-column>
          </el-table></el-form-item>
          <el-form-item><el-button type="primary" @click="insertGrids">提交生成分区</el-button></el-form-item>
        </el-form>
      </div>
    </el-dialog>
    <div v-if="layers.length > 0" class="btn-container">
      <el-button
        type="primary"
        size="medium"
        @click="drawFinish"
      >完成绘制</el-button>
    </div>
  </div>
</template>

<script>
import * as turf from '@turf/turf'
import { mapGetters } from 'vuex'
import { dclassCodeMap, boundaries } from '@/utils/constant'
import 'leaflet.pm'
import 'leaflet.pm/dist/leaflet.pm.css'
import { getVectorContour } from 'kriging-contour/dist/kriging-contour.js'
import L from 'leaflet'
import mapConfig from '@/config/map'
import {
  convertArr2Obj,
  uniqueArr,
  average,
  hotColor,
  boundariesMerge
} from '@/utils'
import { getAll } from '@/api/gridType'
import { addOne } from '@/api/grid'
import { getAll as getPartitions } from '@/api/gridPartition'
export default {
  name: 'UtilsGrid',
  data() {
    return {
      dialogColorVisible: false,
      dialogVisible: false,
      loading: false,
      btnTitle: '插入网格',
      map: {},
      urls: mapConfig.mapTypes[mapConfig.initType],
      show: false,
      layers: [],
      layer: [],
      latlngs: [],
      latlngsArr: [],
      center: '',
      angle: 30,
      angle1: 15,
      distances: [
        12.5, 22.5, 32.5, 42.5, 52.5, 62.5, 72.5, 82.5, 92.5, 102.5, 112.5,
        122.5, 132.5, 142.5
      ],
      polygons: [],
      circlePolygons: [],
      polygonsIntersect: [],
      relation: {},
      baseLayers: [],
      step: 2,
      gridTypes: [],
      gridType: {},
      gridTypeId: '',
      sprinkler: {},
      defaultStep: {},
      featureLayerGroup: null,
      boundaries: turf.lineString(boundaries),
      circleLayer: null,
      gridPartitions: [],
      startAngle: 0,
      endAngle: 360,
      ruleForm: {
        serialno: '',
        angle: 30,
        startAngle: 0,
        endAngle: 360,
        distances: [
          12.5, 22.5, 32.5, 42.5, 52.5, 62.5, 72.5, 82.5, 92.5, 102.5, 112.5,
          122.5, 132.5, 142.5
        ]
      },
      rules: {
        serialno: [
          { required: true, message: '请选择喷灌机', trigger: 'blur' }
        ],
        angle: [
          { required: true, message: '请输入间隔角度', trigger: 'blur' }
        ],
        startAngle: [
          { required: true, message: '请输入起始角度', trigger: 'blur' }
        ],
        endAngle: [
          { required: true, message: '请输入结束角度', trigger: 'blur' }
        ]
      }
    }
  },
  computed: {
    ...mapGetters(['project', 'fields', 'devices']),
    sprinklers() {
      return (
        this.devices.filter((val) => {
          return +val.product_type === +dclassCodeMap.pg
        }) || []
      )
    },
    field() {
      const idx = this.fields.findIndex((val) => {
        return +val.project_id === this.project.id
      })
      return this.fields[idx]
    },
    circlePolygon() {
      const center = [this.project.lng, this.project.lat]
      const radius = 0.15
      const options = {
        steps: 100,
        units: 'kilometers',
        properties: { foo: 'bar' }
      }
      return turf.circle(center, radius, options)
    },
    steps() {
      return (this.gridType && this.gridType.steps) || []
    },
    colors() {
      const res = []
      this.steps.forEach((item) => {
        res.push({ fill: item.color })
      })
      res.push(res[res.length - 1])
      return res
    },
    levelV() {
      const res = []
      this.steps.forEach((item, index) => {
        if (index < this.steps.length - 1) {
          res.push(item.lower)
        } else {
          res.push(item.lower)
          res.push(item.upper)
        }
      })
      return res
    }
  },
  watch: {
    sprinklers: {
      handler(newVal) {
        if (newVal.length > 0) {
          const sprinkler = newVal[0]
          this.ruleForm.serialno = sprinkler.serialno
          this.ruleForm.distances =
            sprinkler.settings &&
              sprinkler.settings.distances || []
        }
      },
      deep: true,
      immediate: true
    },
    'ruleForm.serialno': {
      handler(newVal) {
        const index = this.sprinklers.findIndex((val) => {
          return val.serialno === newVal
        })
        if (index > -1) {
          this.ruleForm.distances = this.sprinklers[index].settings.distances
        } else {
          this.ruleForm.distances = []
        }
      },
      immediate: true
    },
    steps: {
      handler(newVal) {
        if (newVal && newVal.length > 0) {
          if (newVal.length > 0) {
            this.step = newVal.filter((val) => {
              return val.active > 0
            })[0].step
            this.stepsObj = convertArr2Obj(newVal, 'step')
          }
        }
      },
      immediate: true,
      deep: true
    },
    gridTypeId: {
      handler(newVal) {
        if (newVal) {
          this.gridType = this.gridTypes.filter((val) => {
            return val.id === newVal
          })[0]
          this.defaultStep = this.gridType.steps.filter((val) => {
            return val.active > 0
          })[0]
          this.clearKriging()
          this.getPartitions()
        }
      },
      immediate: true
    }
  },
  mounted() {
    this.initMap()
    this.center = [this.project.lng, this.project.lat].join(',')
    this.getAll()
  },
  methods: {
    addDistance() {
      this.ruleForm.distances.push({
        distance: '',
        spstart: '',
        spend: ''
      })
    },
    deleteDistance(index) {
      if (this.ruleForm.distances.length === 1) {
        this.$message.error('至少需要有一条数据')
        return
      }
      this.ruleForm.distances.splice(index, 1)
    },
    handleCommand(command) {
      this.addLayer(command.data)
    },
    async getPartitions() {
      const {
        data: { data }
      } = await getPartitions({ grid_type_id: this.gridTypeId })
      this.gridPartitions = data
    },
    addLayer(data) {
      const awc = data.map((val) => {
        const { lat, lng, awc600, NRCT, value } = val
        return {
          lat,
          lng,
          val: awc600 || NRCT || value || 0
        }
      })
      this.startKriging(awc)
    },
    startKriging(awc) {
      let points = awc

      if (this.gridType.name !== '无人机') {
        const data = average(awc.map((val) => +val.val))
        points = boundariesMerge(awc, data)
      }

      const positionData = {
        type: 'FeatureCollection',
        features: points.map((i) => {
          return {
            type: 'Feature',
            properties: {
              value: i.val
            },
            geometry: {
              type: 'Point',
              coordinates: [+i.lng, +i.lat]
            }
          }
        })
      }
      this.showKrigingVector(positionData)
    },
    showKrigingVector(positionData) {
      this.clearKriging()
      this.circleLayer = new L.Circle([this.field.longitude, this.field.latitude], +this.field.radius, {
        color: '#409eff',
        fillColor: '#b7ecef',
        fillOpacity: 1,
        weight: 0
      })
      this.circleLayer.addTo(this.map)
      const kriging_contours = getVectorContour(
        positionData,
        'value',
        {
          model: 'exponential',
          sigma2: 0,
          alpha: 100
        },
        this.levelV,
        this.boundaries
      )

      const features_filter = []
      kriging_contours.features.forEach((layer) => {
        let intersection = null
        try {
          intersection = turf.intersect(layer, this.circlePolygon)
        } catch (e) {
          layer = turf.buffer(layer, 0)
          intersection = turf.intersect(layer, this.circlePolygon)
        }
        if (intersection != null) {
          intersection.properties = layer.properties
          features_filter.push(intersection)
        }
      })

      L.geoJSON(features_filter, {
        style: (feature) => {
          return {
            fillColor: hotColor(
              feature.properties.contour_value,
              this.colors,
              this.levelV
            ),
            weight: 0,
            fillOpacity: 0.6
          }
        }
      }).addTo(this.featureLayerGroup)
    },
    // 清空图层
    clearKriging() {
      if (this.circleLayer) {
        this.map.removeLayer(this.circleLayer)
      }
      this.layers.reverse().forEach((item, index) => {
        delete item.layer
        delete item.polygon
      })
      this.featureLayerGroup.clearLayers()
    },
    async getAll() {
      const {
        data: { data }
      } = await getAll({ field_id: this.field.id })
      this.gridTypes = data
      this.gridType = this.gridTypes.filter((val) => {
        return val.active > 0
      })[0]
      this.gridTypeId = this.gridType.id
      this.step = this.gridType.steps.filter((val) => {
        return val.active > 0
      })[0].step

      this.getPartitions()
    },
    changeStep(step) {
      this.step = step
    },
    drawFinish() {
      console.log(this.layers)
      const unFinished = this.layers.filter((val) => {
        return !val.layer.options.fillColor
      }).length
      if (unFinished > 0) {
        this.dialogColorVisible = true
      }
    },
    _drawFinish() {
      const index = this.steps.findIndex((item) => {
        return +item.step === +this.step
      })
      const step = this.steps[index]
      this.layers.forEach((item) => {
        if (!this.relation[item.layer._leaflet_id]) {
          item.layer.setStyle({
            fillColor: step.color,
            fillOpacity: 1
          })
          item.color = step.color
          item.step = step.step
        }
      })
      this.$confirm('确定提交生成的新分区吗？', '操作确认', { type: 'warning' })
        .then(() => {
          const arr = []
          this.layers.reverse().forEach((item, index) => {
            const layer = item.layer
            const _leaflet_id = layer._leaflet_id
            const _latlngs = layer._latlngs[0]
            item.kml = _latlngs
              .map((val) => [val.lng, val.lat].join(','))
              .join(';')
            item.name =
              item.idx +
              '-' +
              (index + 1 - this.distances.length * (item.idx - 1))
            delete item.layer
            delete item.polygon
            if (this.relation[_leaflet_id]) {
              item.step = this.relation[_leaflet_id]
              item.color = this.stepsObj[this.step].color
            }
            arr.push(item)
          })
          const postData = {
            field_id: this.field.id,
            grid_type_id: this.gridTypeId,
            start_angle: this.startAngle,
            end_angle: this.endAngle,
            angle: this.angle,
            grids: arr
          }
          this.addOne(postData)
        })
        .catch((e) => { console.log(e) })
    },
    async addOne(postData) {
      const { msg } = await addOne(postData)
      this.$message.success(msg)
    },
    insertGrids() {
      if (this.layers.length > 0) {
        this.$confirm('检测到现在已经有分区，确定要重新分区吗？', '操作确认', {
          type: 'warning'
        })
          .then(() => {
            this._insertGrids()
          })
          .catch(() => {})
      } else {
        this._insertGrids()
      }
    },
    _insertGrids() {
      if (!this.ruleForm.angle) {
        this.$message.error('请输入分割角度')
        return
      }
      // if (!this.ruleForm.distances) {
      //   this.$message.error("该喷灌机未设置各喷头阵列距离中心点位置");
      //   return;
      // }

      this.dialogVisible = false

      this.polygons = []
      this.circlePolygons = []
      this.polygonsIntersect = []
      this.layers = []

      var center = turf.point([+this.field.latitude, +this.field.longitude])
      var radius = +this.field.radius / 1000
      const angle = this.ruleForm.angle
      const workAngle = Math.abs(this.ruleForm.endAngle - this.ruleForm.startAngle)
      for (
        let i = this.ruleForm.startAngle / angle;
        i < this.ruleForm.startAngle / angle + workAngle / angle;
        i++
      ) {
        var bearing1 = i * angle
        var bearing2 = (i + 1) * angle

        var sector = turf.sector(center, radius, bearing1, bearing2)
        let latlngs = sector.geometry.coordinates[0]
        latlngs = latlngs.map((val) => [val[1], val[0]])
        // eslint-disable-next-line no-undef
        const polygon = L.polygon(latlngs, {
          color: 'rgb(51,136,255)',
          fillColor: 'red',
          fillOpacity: '0.4',
          weight: 2
        })
        this.polygons.push(polygon)
      }

      // let distances = this.distances.map((val) => val.distance);
      let distances = []
      if (this.ruleForm.distances) {
        distances = uniqueArr(this.ruleForm.distances.map((val) => val.distance) || [])
      }

      distances.forEach((item) => {
        var bearing3 = 0
        var bearing4 = 360
        var sector1 = turf.sector(center, item / 1000, bearing3, bearing4)
        let latlngs = sector1.geometry.coordinates[0]
        latlngs = latlngs.map((val) => [val[1], val[0]])
        // eslint-disable-next-line no-undef
        const circlePolygon = L.polygon(latlngs, {
          color: 'rgb(51,136,255)',
          fillColor: 'red',
          fillOpacity: '0.4'
        })
        this.circlePolygons.push(circlePolygon)
      })

      const res = []
      this.polygons.forEach((item, index) => {
        const latlngs = item._latlngs[0].map((val) => [val.lat, val.lng])
        latlngs[latlngs.length] = latlngs[0]

        const temp = []
        this.circlePolygons.forEach((citem, cindex) => {
          const latlngsCircle = citem._latlngs[0].map((val) => [
            val.lat,
            val.lng
          ])
          latlngsCircle[latlngsCircle.length] = latlngsCircle[0]

          var intersection = turf.intersect(
            turf.polygon([latlngs]),
            turf.polygon([latlngsCircle])
          )
          const semicircle = intersection.geometry.coordinates[0]
          temp.push({
            angle: (index + 1) * this.angle,
            distance: distances[cindex],
            polygon: semicircle
          })
        })
        res.push(temp)
      })

      const polygons = []
      res.forEach((item, index) => {
        item.forEach((citem, cindex) => {
          if (cindex === 0) {
            polygons.push({
              polygon: citem.polygon,
              argstart: this.angle * index,
              argend: citem.angle,
              idx: index + 1,
              spstart: this.ruleForm.distances[cindex].spstart,
              spend: this.ruleForm.distances[cindex].spend,
              disstart: 0,
              disend: citem.distance
            })
          } else {
            var difference = turf.difference(
              turf.polygon([citem.polygon]),
              turf.polygon([item[cindex - 1].polygon])
            )
            polygons.push({
              polygon: difference.geometry.coordinates[0],
              argstart: this.angle * index,
              argend: citem.angle,
              idx: index + 1,
              spstart: this.ruleForm.distances[cindex].spstart,
              spend: this.ruleForm.distances[cindex].spend,
              disstart: distances[cindex - 1],
              disend: citem.distance
            })
          }
        })
      })

      polygons.reverse().forEach((item, index) => {
        // eslint-disable-next-line no-undef
        const layer = L.polygon(item.polygon, {
          color: '#000',
          fillColor: '',
          fillOpacity: 0,
          weight: 1
        }).addTo(this.map)
        layer.on('click', (e) => {
          e.target.setStyle({
            fillColor: this.stepsObj[this.step].color,
            fillOpacity: 1
          })
          this.relation[e.sourceTarget._leaflet_id] = this.step
        })
        item.layer = layer
        item.area = turf.area(
          turf.polygon([item.polygon.map((val) => [val[1], val[0]])])
        )
        this.layers.push(item)
      })
    },
    showDialog() {
      this.$refs.mainForm.show()
    },
    initMap() {
      this.urls.forEach((item) => {
        // eslint-disable-next-line no-undef
        this.baseLayers.push(L.tileLayer(item))
      })

      // eslint-disable-next-line no-undef
      const map = L.map('map', {
        center: [+this.field.longitude, +this.field.latitude],
        zoom: 18,
        zoomControl: false,
        maxZoom: 18,
        attributionControl: false,
        layers: this.baseLayers
      })
      map.pm.setLang('zh')
      map.pm.addControls({
        position: 'topleft',
        drawPolygon: true, // 绘制多边形
        drawMarker: false, // 绘制标记点
        drawCircleMarker: false, // 绘制圆形标记
        drawPolyline: false, // 绘制线条
        drawRectangle: true, // 绘制矩形
        drawCircle: false, // 绘制圆圈
        editMode: false, // 编辑多边形
        dragMode: false, // 拖动多边形
        cutPolygon: false, // 添加一个按钮以删除多边形里面的部分内容
        removalMode: true // 清除多边形
      })
      this.map = map

      this.map.pm.setPathOptions({
        color: 'blue',
        fillColor: 'pink',
        fillOpacity: 0.4
      })
      this.map.pm.setLang('zh')

      // 创建图层
      this.map.on('pm:create', (e) => {
        this.layers.push(e.layer)
        this.map.pm.disableDraw()
      })

      // 移除图层
      this.map.on('pm:remove', (e) => {
        const index = this.getLeafletId(e)
        this.layers.splice(index, 1)
      })

      this.featureLayerGroup = new L.FeatureGroup()
        .addTo(this.map)
        .bringToBack()
    },
    getLeafletId(e) {
      const id = e.layer._leaflet_id
      const index = this.latlngsArr.findIndex((val) => {
        return val.id === id
      })
      return index
    }
  }
}
</script>
<style lang="scss">
.leaflet-tooltip-top:before {
  border-top: none;
}
.leaflet-tooltip {
  background: none;
  border: none;
  box-shadow: none;
}
.tip-box {
  color: #fff;
  font-size: 18px;
}
.leaflet-touch .leaflet-bar a {
  width: 30px;
  height: 30px;
}
.button-container .leaflet-pm-actions-container {
  left: 61px;
}
</style>

<style lang="scss" scoped>
.app-container {
  position: relative;
  .tools {
    position: absolute;
    top: 24px;
    right: 24px;
    z-index: 999;
  }
  .color-board {
    position: absolute;
    top: 72px;
    right: 24px;
    z-index: 999;
  }
  .btn-container {
    position: absolute;
    right: 24px;
    bottom: 24px;
    z-index: 9999;
  }
}
.container {
  position: relative;
  width: 100%;
  height: calc(100vh - 50px);
  .btn-container {
    position: absolute;
    right: 24px;
    bottom: 24px;
    z-index: 9999;
  }
}
.colors {
  position: absolute;
  top: 24px;
  left: 64px;
  z-index: 999;
  dl {
    align-items: center;
    font-size: 12px;
    dt {
      display: flex;
      height: 36px;
      line-height: 35px;
      text-align: center;
      margin-right: 4px;
      color: #000;
      align-items: center;
      padding: 0 12px;
      font-weight: bold;
      &:hover {
        opacity: 0.9;
        cursor: pointer;
      }
    }
  }
}
</style>
